
/***********************************************
*   Project: Virtual Manufacturing System      *
*                                              *
*   Date: 03.08.12                             *
*                                              *
*   File: velData.h                            *
* 					       *
*   Author: Rafal Pielech                      *
*   E-mail: rafalpielech@hotmail.com           *
************************************************/

#ifndef VELDATA_H
#define VELDATA_H

#include <math.h>
#include "gmfParser.h"


template < class VTK_real , class VTK_integer > class velData
{
         protected:
                      VTK_real                ** verticesArray;
                      VTK_real                 * transMatrix;
                      VTK_real                ** normalvArray;
                      VTK_integer             ** indicesArray;
                      VTK_integer                nOfVertices;
                      VTK_integer                nOfFaces;

                      float                    * colorVector;

                      gmfParser< VTK_real ,
                                 VTK_integer > * internalParser;


                      void                       vtkInitTransMatrix( void );
                      void                       vtkInitColorVector( void );
                      void                       vtkLoadIdentity   ( VTK_real * matrix = NULL );

                      short                      stateFlag;

                      //------------------------------------------------------------------------------------

                      void vtkVectDiff( const VTK_real * v1, const VTK_real * v2, VTK_real * result );

                      void vtkVectCrossP( const VTK_real * v1, const VTK_real * v2, VTK_real * result );

                      virtual void vtkCalculateNormalv( void ) = 0;

                      //------------------------------------------------------------------------------------

                      void                       vtkClear( void );

            public:
                                                 velData( void );
                      void                       vtkLoadGeometry( const string fname );

                      short                      vtkGood( void );

                      const VTK_real          ** vtkGetVerticesArray( void );
                      const VTK_integer       ** vtkGetIndicesArray ( void );
                      const VTK_real          ** vtkGetNormalvArray ( void );
                            VTK_integer          vtkGetNofVertices  ( void );
                            VTK_integer          vtkGetNofFaces     ( void );

                      const float              * vtkGetColor( void );
                      void                       vtkSetColor( const float * color );
                      void                       vtkTransformObject( const VTK_real * matrix );
                      
                      const VTK_real           * vtkGetTransMatrix( void );

                      virtual                   ~velData( void );
};

// --------------------------------------------------------------------------------
// ------------------------ < Implementation > ------------------------------------

template < class VTK_real , class VTK_integer >
velData< VTK_real , VTK_integer > :: velData( void )
{
        verticesArray = NULL;
        indicesArray  = NULL;
        normalvArray  = NULL;
        colorVector   = NULL;
        transMatrix   = NULL;

        internalParser = NULL;

        nOfVertices   = 0;
        nOfFaces      = 0;

        stateFlag     = 1;
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
void
velData< VTK_real , VTK_integer > :: vtkClear( void )
{
      VTK_integer i;
      
        if( verticesArray != NULL )
        {
            for( i = 0; i < nOfVertices; i++ )
            {
                  delete[] verticesArray[ i ];
                  verticesArray[ i ] = NULL;
            }
            delete[] verticesArray;
            verticesArray = NULL; 
        }
        
        if( normalvArray != NULL ) 
        {
            for( i = 0; i < nOfFaces; i++ )
            {
                  delete[] normalvArray[ i ];
                  normalvArray[ i ] = NULL;
            }
                             
            delete[] normalvArray;
            normalvArray = NULL; 
        }

        if( indicesArray != NULL ) 
        {
            for( i = 0; i < nOfFaces; i++ )
            {
                  delete[] indicesArray[ i ];
                  indicesArray[ i ] = NULL;
            }
                             
            delete[] indicesArray;
            indicesArray = NULL; 
        }
        
        if( colorVector   != NULL ) { delete[] colorVector;    colorVector   = NULL; }
        if( transMatrix   != NULL ) { delete[] transMatrix;    transMatrix   = NULL; }

        nOfVertices = 0;
        nOfFaces    = 0;
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
void
velData< VTK_real , VTK_integer > :: vtkLoadIdentity( VTK_real * matrix )
{
      VTK_real * pointer;
 
        if( matrix != NULL )
        {
            pointer = matrix;
        }
        else
        {
            if( transMatrix != NULL ) pointer = transMatrix;
            else 
                return;
        }
        
        
        for( short i = 0; i < 16; i++ )
        {
            if( (i % 5) == 0 )
            {
                  pointer[ i ] = 1.0;
                  continue;
            }
            pointer[ i ] = 0.0;
        }
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
void
velData< VTK_real , VTK_integer > :: vtkInitTransMatrix( void )
{

        transMatrix = new VTK_real [ 16 ];  // throws std :: bad_alloc
        vtkLoadIdentity();
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
void
velData< VTK_real , VTK_integer > :: vtkInitColorVector( void )
{

        colorVector = new float [ 4 ];

        colorVector[ 0 ] = 1.0;  // sets to white
        colorVector[ 1 ] = 1.0;
        colorVector[ 2 ] = 1.0;
        colorVector[ 3 ] = 1.0;
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
void
velData< VTK_real , VTK_integer > :: vtkLoadGeometry( const string fname )
{

        vtkClear();
        internalParser->loadDataFile( fname );

        short failure = 0 , success = 1;

           try
           {
                if( !internalParser->good() ) throw( failure ); // if not then ...

                // get data from file parser

                pair< VTK_real ** , VTK_integer ** > arrays;
                pair< VTK_integer , VTK_integer    > counters;

                arrays   = internalParser->getVertices_FaceIndices();
                counters = internalParser->getNofVertices_Faces();

                verticesArray = arrays.first;
                indicesArray  = arrays.second;

                nOfVertices   = counters.first;
                nOfFaces      = counters.second;

                vtkInitTransMatrix(); // loads identity matrix and can throw std::bad_alloc exception
                vtkInitColorVector(); // sets color vector (RGBA) to white - || -    - || -   - || -

                vtkCalculateNormalv(); // can throw std::bad_alloc only

              throw( success ); // EVERYTHING WENT OK

           }
           catch( short exc )
           {
                stateFlag = exc;
                if( stateFlag == 0 ) vtkClear();
           }
           catch( ... )
           {
                stateFlag = 0;
                vtkClear();
           }
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
short
velData< VTK_real , VTK_integer > :: vtkGood( void )
{
        return stateFlag;
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
const float *
velData< VTK_real , VTK_integer > :: vtkGetColor( void )
{
        float * colorv = colorVector;
        return const_cast< const float * >( colorv );
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
void
velData< VTK_real , VTK_integer > :: vtkSetColor( const float * color )
{
        colorVector[ 0 ] = color[ 0 ];
        colorVector[ 1 ] = color[ 1 ];
        colorVector[ 2 ] = color[ 2 ];
        colorVector[ 3 ] = color[ 3 ];
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
const VTK_real *
velData< VTK_real , VTK_integer > :: vtkGetTransMatrix( void )
{
      VTK_real * TMatrix = transMatrix;
      return const_cast< const VTK_real * >( TMatrix );
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
const VTK_real **
velData< VTK_real , VTK_integer > :: vtkGetVerticesArray( void )
{
        VTK_real ** vertices = verticesArray;
        return const_cast< const VTK_real ** >( vertices );
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
const VTK_integer **
velData< VTK_real , VTK_integer > :: vtkGetIndicesArray( void )
{
        VTK_integer ** indices = indicesArray;
        return const_cast< const VTK_integer ** >( indices );
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
const VTK_real **
velData< VTK_real , VTK_integer > :: vtkGetNormalvArray( void )
{

        VTK_real ** normalv = normalvArray;
        return static_cast< const VTK_real ** >( normalv );
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
VTK_integer
velData< VTK_real , VTK_integer > :: vtkGetNofVertices( void )
{
        return nOfVertices;
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
VTK_integer
velData< VTK_real , VTK_integer > :: vtkGetNofFaces( void )
{
        return nOfFaces;
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
void
velData< VTK_real , VTK_integer > :: vtkTransformObject( const VTK_real * matrix )
{

    VTK_integer i;
    
        VTK_real * tmp = new VTK_real [16];
    
        vtkLoadIdentity( tmp );
        
      /* tm_11 */ transMatrix[0]  = tmp[0] * matrix[0] + tmp[4] * matrix[1] + tmp[8] * matrix[2] + tmp[12] * matrix[3];
      /* tm_12 */ transMatrix[4]  = tmp[0] * matrix[4] + tmp[4] * matrix[5] + tmp[8] * matrix[6] + tmp[12] * matrix[7];
      /* tm_13 */ transMatrix[8]  = tmp[0] * matrix[8] + tmp[4] * matrix[9] + tmp[8] * matrix[10] + tmp[12] * matrix[11];
      /* tm_14 */ transMatrix[12] = tmp[0] * matrix[12] + tmp[4] * matrix[13] + tmp[8] * matrix[14] + tmp[12] * matrix[15];

      /* tm_21 */ transMatrix[1]  = tmp[1] * matrix[0] + tmp[5] * matrix[1] + tmp[9] * matrix[2] + tmp[13] * matrix[3];
      /* tm_22 */ transMatrix[5]  = tmp[1] * matrix[4] + tmp[5] * matrix[5] + tmp[9] * matrix[6] + tmp[13] * matrix[7];
      /* tm_23 */ transMatrix[9]  = tmp[1] * matrix[8] + tmp[5] * matrix[9] + tmp[9] * matrix[10] + tmp[13] * matrix[11];
      /* tm_24 */ transMatrix[13] = tmp[1] * matrix[12] + tmp[5] * matrix[13] + tmp[9] * matrix[14] + tmp[13] * matrix[15];
    
      /* tm_31 */ transMatrix[2]  = tmp[2] * matrix[0] + tmp[6] * matrix[1] + tmp[10] * matrix[2] + tmp[14] * matrix[3];
      /* tm_32 */ transMatrix[6]  = tmp[2] * matrix[4] + tmp[6] * matrix[5] + tmp[10] * matrix[6] + tmp[14] * matrix[7];
      /* tm_33 */ transMatrix[10] = tmp[2] * matrix[8] + tmp[6] * matrix[9] + tmp[10] * matrix[10] + tmp[14] * matrix[11];
      /* tm_34 */ transMatrix[14] = tmp[2] * matrix[12] + tmp[6] * matrix[13] + tmp[10] * matrix[14] + tmp[14] * matrix[15];
    
      /* tm_41 */ transMatrix[3]  = tmp[3] * matrix[0] + tmp[7] * matrix[1] + tmp[11] * matrix[2] + tmp[15] * matrix[3];
      /* tm_42 */ transMatrix[7]  = tmp[3] * matrix[4] + tmp[7] * matrix[5] + tmp[11] * matrix[6] + tmp[15] * matrix[7];
      /* tm_43 */ transMatrix[11] = tmp[3] * matrix[8] + tmp[7] * matrix[9] + tmp[11] * matrix[10] + tmp[15] * matrix[11];
      /* tm_44 */ transMatrix[15] = tmp[3] * matrix[12] + tmp[7] * matrix[13] + tmp[11] * matrix[14] + tmp[15] * matrix[15];
    
      delete[] tmp;
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
void
velData< VTK_real , VTK_integer > :: vtkVectDiff( const VTK_real * v1, const VTK_real * v2, VTK_real * result )
{
            result[0] = v2[0]-v1[0];
            result[1] = v2[1]-v1[1];
            result[2] = v2[2]-v1[2]; 
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
void
velData< VTK_real , VTK_integer > :: vtkVectCrossP( const VTK_real * v1, const VTK_real * v2, VTK_real * result )
{
        VTK_real vlength;

        result[0] = v1[1]*v2[2]-v2[1]*v1[2];
        result[1] = v2[0]*v1[2]-v1[0]*v2[2];
        result[2] = v1[0]*v2[1]-v2[0]*v1[1];

        vlength = sqrt( result[0]*result[0] + result[1]*result[1] + result[2]*result[2] );
        // sqrt takes double but VTK_real can alternate between float and double ...

        result[0] /= vlength;
        result[1] /= vlength;
        result[2] /= vlength;
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
velData< VTK_real , VTK_integer > :: ~velData( void )
{
        vtkClear();

        // only destructor can release internal parser

        delete internalParser;
}

// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
class velData_tri : public velData< VTK_real , VTK_integer >
{
        protected:
                      void vtkCalculateNormalv( void );

        public:
                      velData_tri( void );
                      velData_tri( const string fname );
};


// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------

// --------------------------------------------------------------------------------
// ------------------------ < Implementation > ------------------------------------

template < class VTK_real , class VTK_integer >
velData_tri< VTK_real , VTK_integer > :: velData_tri( void )
{
       internalParser = new gmfParser_tri< VTK_real , VTK_integer >(); // exception may be thrown !!!
}


// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
velData_tri< VTK_real , VTK_integer > :: velData_tri( const string fname )
{
        internalParser = new gmfParser_tri< VTK_real , VTK_integer >(); // exception may be thrown !!!
        vtkLoadGeometry( fname );
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
void
velData_tri< VTK_real , VTK_integer > :: vtkCalculateNormalv( void )
{

    VTK_integer i;

    normalvArray = new VTK_real * [ nOfFaces ];

    for( i = 0; i < nOfFaces; i++ ) normalvArray[ i ] = NULL;
    // set them all to NULL at start

    for( i = 0; i < nOfFaces; i++ ) normalvArray[ i ] = new VTK_real [ 3 ];


    VTK_real vector_1[ 3 ] , vector_2[ 3 ];

    VTK_integer face;

    for( face = 0; face < nOfFaces; face++ )
    {
        vtkVectDiff( verticesArray[ indicesArray[ face ][ 0 ] ] ,
                     verticesArray[ indicesArray[ face ][ 1 ] ] , vector_1 );
        
        vtkVectDiff( verticesArray[ indicesArray[ face ][ 0 ] ] ,
                     verticesArray[ indicesArray[ face ][ 2 ] ] , vector_2 );                     


        vtkVectCrossP( vector_1 , vector_2 , normalvArray[ face ] );
    }
}


// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
class velData_poly : public velData< VTK_real , VTK_integer >
{
        protected:
                      void vtkCalculateNormalv( void );

        public:
                      velData_poly( void );
                      velData_poly( const string fname );
};


// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------

// --------------------------------------------------------------------------------
// ------------------------ < Implementation > ------------------------------------

template< class VTK_real , class VTK_integer >
velData_poly< VTK_real , VTK_integer > :: velData_poly( void )
{
        internalParser = new gmfParser_poly< VTK_real , VTK_integer >(); // exception may be thrown !!!
}

// --------------------------------------------------------------------------------

template< class VTK_real , class VTK_integer >
velData_poly< VTK_real , VTK_integer > :: velData_poly( const string fname )
{
        internalParser = new gmfParser_poly< VTK_real , VTK_integer >(); // exception may be thrown !!!
        vtkLoadGeometry( fname );
}

// --------------------------------------------------------------------------------

template< class VTK_real , class VTK_integer >
void
velData_poly< VTK_real , VTK_integer > :: vtkCalculateNormalv( void )
{
        VTK_integer i;

        normalvArray = new VTK_real * [ nOfFaces ];  // ( new throws sdt::bad_alloc on failure )

        for( i = 0; i < nOfFaces; i++ ) normalvArray[ i ] = NULL;
        // set them all to NULL at start

        for( i = 0; i < nOfFaces; i++ ) normalvArray[ i ] = new VTK_real [ 3 ];


        VTK_real vector_1[ 3 ] , vector_2[ 3 ];

        VTK_integer face;

           for( face = 0; face < nOfFaces; face++ )
           {
               
               // !!! at indicesArray[ face ][ 0 ] face descriptor is located !!!
                              
               vtkVectDiff( verticesArray[ indicesArray[ face ][ 1 ] ] , verticesArray[ indicesArray[ face ][ 2 ] ] , vector_1 );
               
               vtkVectDiff( verticesArray[ indicesArray[ face ][ 1 ] ] , verticesArray[ indicesArray[ face ][ 3 ] ] , vector_2 );

               vtkVectCrossP( vector_1 , vector_2 , normalvArray[ face ] );
           }
}

#endif